package br.ufmg.vod.wbr.graphs;

import java.util.Arrays;


public class FastDirectedGraph  implements br.ufmg.vod.wbr.api.DirectedGraph{
	
	protected int[][] inEdges;
	protected int[][] outEdges;

	protected long maxInDegree;
	protected long maxOutDegree;
	protected int edgeCount;
	protected int numVertex;

	protected FastDirectedGraph(int[][] inEdges, int[][] outEdges) {
		this.inEdges = inEdges;
		this.outEdges = outEdges;
		this.numVertex = Math.max(inEdges.length, outEdges.length);
		
		//Compacting
		this.edgeCount = 0;
		for (int u = 0; u < inEdges.length; u++) {
			//inEdges
			int[] oldArray = inEdges[u];
			Arrays.sort(inEdges[u]);
			for (int i = 0; i < oldArray.length; i++) {
				if( oldArray[i] >= outEdges.length){
					int[] newArray = new int[i];
					System.arraycopy(oldArray, 0, newArray, 0, i);
					inEdges[u] = newArray;
					break;
				}
			}
			this.edgeCount += inEdges[u].length;
		}
		
		for (int u = 0; u < outEdges.length; u++) {
			//outEdges
			int[] oldArray = outEdges[u];
			Arrays.sort(outEdges[u]);
			for (int i = 0; i < oldArray.length; i++) {
				if(oldArray[i] >= inEdges.length){
					int[] newArray = new int[i];
					System.arraycopy(oldArray, 0, newArray, 0, i);
					outEdges[u] = newArray;
					break;
				}
			}
			this.edgeCount += outEdges[u].length;
		}
	}
	
	@Override
	public int getInDegree(int vertex) {
		return this.inEdges[vertex].length;
	}

	@Override
	public int[] getIncomingEdges(int vertex) {
		return this.inEdges[vertex];
	}

	@Override
	public int getOutDegree(int vertex) {
		return this.outEdges[vertex].length;
	}
	
	@Override
	public int[] getOutgoingEdges(int vertex) {
		return this.outEdges[vertex];
	}

	@Override
	public boolean containsEdge(int vertex1, int vertex2) {
		return Arrays.binarySearch( this.outEdges[vertex1], vertex2) != -1;
	}

	@Override
	public boolean containsVertex(int vertex) {
		return vertex >= 0 && vertex < this.outEdges.length;
	}

	@Override
	public int getDegree(int vertex) {
		return this.getInDegree(vertex)+this.getOutDegree(vertex);
	}

	@Override
	public int[] getEdges(int vertex) {
		return this.getOutgoingEdges(vertex);
	}

	@Override
	public int getNumEdges() {
		return this.edgeCount;
	}

	@Override
	public int getNumVertex() {
		return this.numVertex;
	}


	@Override
	public int[][] getAllIncomingEdges() {
		return this.inEdges;
	}


	@Override
	public int[][] getAllOutgoinEdges() {
		return this.outEdges;
	}


	@Override
	public int[][] getAllEdges() {
		return this.outEdges;
	}
	
	@Override
	public void transpose(){
		Object aux = null;
		
		aux = this.inEdges;
		this.inEdges = this.outEdges;
		this.outEdges = (int[][]) aux;
		
		aux = this.maxInDegree;
		this.maxInDegree = this.maxOutDegree;
		this.maxOutDegree = (Long) aux;
	}
}
